package expo.modules.helloworldexpomodules

import android.content.Context
import android.net.Uri
import com.tencent.cos.xml.CosXmlServiceConfig
import com.tencent.cos.xml.CosXmlSimpleService
import com.tencent.cos.xml.exception.CosXmlClientException
import com.tencent.cos.xml.exception.CosXmlServiceException
import com.tencent.cos.xml.transfer.COSXMLUploadTask
import com.tencent.cos.xml.transfer.TransferConfig
import com.tencent.cos.xml.transfer.TransferManager
import com.tencent.qcloud.core.auth.ShortTimeCredentialProvider
import java.io.File
import java.net.URL
import java.util.concurrent.CountDownLatch

object PutObject {
    private var isServiceConfigured = false
    private var transferManager: TransferManager? = null

    private const val DEFAULT_REGION = "ap-shanghai"
    private const val SECRET_ID = "AKIDhIjwytywqdG5nIdqtnbGxshOxLtKdu58"
    private const val SECRET_KEY = "uZ6Z0Qly23vc5OXdcO8jeSIxZ2TsBc2X"

    fun setupCOSService(context: Context) {
        if (isServiceConfigured) return
        isServiceConfigured = true

        val serviceConfig = CosXmlServiceConfig.Builder()
            .setRegion(DEFAULT_REGION)
            .isHttps(true)
            .builder()

        // 有效期设置为 1 天（单位秒）
        val credentialProvider = ShortTimeCredentialProvider(SECRET_ID, SECRET_KEY, 86400)
        val cosXmlService = CosXmlSimpleService(context, serviceConfig, credentialProvider)
        val transferConfig = TransferConfig.Builder().build()

        transferManager = TransferManager(cosXmlService, transferConfig)
    }

    fun uploadLocalFile(
        context: Context,
        filePath: String,
        objectKey: String,
        bucket: String,
        region: String = DEFAULT_REGION,
        progress: ((sent: Long, totalSent: Long, total: Long) -> Unit)? = null,
        completion: (fileUrl: URL?, result: COSXMLUploadTask.COSXMLUploadTaskResult?, error: Exception?) -> Unit
    ) {
        val safeRegion = region
        val fileUri = if (filePath.startsWith("file://")) Uri.parse(filePath) else Uri.fromFile(File(filePath))
        val file = File(fileUri.path!!)

        val task: COSXMLUploadTask = transferManager!!.upload(
            bucket,
            objectKey,
            file.absolutePath,
            null
        )

        task.setCosXmlProgressListener { complete, target ->
            progress?.invoke(target - complete, complete, target)
        }

        task.setCosXmlResultListener(object : com.tencent.cos.xml.listener.CosXmlResultListener {
            override fun onSuccess(
                request: com.tencent.cos.xml.model.CosXmlRequest,
                result: com.tencent.cos.xml.model.CosXmlResult
            ) {
                if (result is COSXMLUploadTask.COSXMLUploadTaskResult) {
                    val urlStr = "https://${bucket}.cos.${safeRegion}.myqcloud.com/${objectKey}"
                    completion(URL(urlStr), result, null)
                } else {
                    completion(null, null, ClassCastException("Unexpected result type: ${result::class.java.name}"))
                }
            }

            override fun onFail(
                request: com.tencent.cos.xml.model.CosXmlRequest,
                clientException: CosXmlClientException?,
                serviceException: CosXmlServiceException?
            ) {
                val error = clientException ?: serviceException ?: Exception("Unknown COS Upload Error")
                completion(null, null, error)
            }
        })
    }

    fun batchUploadLocalFiles(
        context: Context,
        filePaths: List<String>,
        bucket: String,
        region: String = DEFAULT_REGION,
        onSingleFinish: ((index: Int, path: String, url: URL?, result: COSXMLUploadTask.COSXMLUploadTaskResult?, error: Exception?) -> Unit)? = null,
        onAllFinish: (() -> Unit)? = null
    ) {
        val group = CountDownLatch(filePaths.size)

        filePaths.forEachIndexed { index, path ->
            val fileName = File(path).name
            val objectKey = fileName

            uploadLocalFile(
                context,
                path,
                objectKey,
                bucket,
                region,
                progress = null,
                completion = { url, result, error ->
                    onSingleFinish?.invoke(index, path, url, result, error)
                    group.countDown()
                }
            )
        }

        Thread {
            group.await()
            onAllFinish?.invoke()
        }.start()
    }
}
